import { Processor, Element } from "@frontity/html2react/types";
import { Packages } from "../../types";
import { Head } from "frontity";
import { httpToHttps } from "../utils";

/**
 * Props for the {@link AMPIframe} component.
 */
interface IFrameProps {
  /**
   * Title for the iframe.
   */
  title: string;

  /**
   * Src of the iframe element.
   */
  src: string;

  /**
   * Height of the iframe. Typically should be set in the WordPress content.
   */
  height: string;

  /**
   * Corresponds to the `allowfullscreen` property of the iframe element.
   */
  allowFullScreen: boolean;

  /**
   * Corresponds to the `sandbox` property of the iframe element.
   */
  sandbox: boolean;

  /**
   * The className that might be passed to the component after being
   * having been generated by the emotion babel plugin.
   */
  className: string;
}

/**
 * The component that renders an amp-iframe component in place of a regular
 * iframe and adds the required AMP script for amp-iframe in the head.
 *
 * @param props - The props to pass the the amp-iframe.
 *
 * @returns A react component.
 */
const AMPIframe: React.FC<IFrameProps> = ({
  title,
  src,
  height,
  allowFullScreen,
  sandbox,
  className,
  ...rest
}) => {
  return (
    <>
      <Head>
        <script
          // We have to explicitly pass undefined, otherwise the attribute is
          // passed to the DOM like async="true" and AMP does not allow that.
          async={undefined}
          custom-element="amp-iframe"
          src="https://cdn.ampproject.org/v0/amp-iframe-0.1.js"
        />
      </Head>
      <amp-iframe
        {...rest}
        class={className}
        title={title || ""}
        src={src}
        layout="fixed-height"
        // If the attribute's value is truthy, we set it to "" so that
        // the attribute appears as a boolean without a value, like: <video loop>
        // This is required per AMP validation rules
        // https://stackoverflow.com/a/50996065/2638310
        {...(allowFullScreen ? { allowFullScreen: "" } : undefined)}
        sandbox={`allow-scripts allow-same-origin ${sandbox ? sandbox : ""}`}
        width="auto" // has to be set to auto if used with fixed-height layout
        height={parseInt(height, 10) || 150} // This is mimicking the browser default of 150px
      />
    </>
  );
};

/**
 * Interface for the iframe element that is processed by the AMP image processor.
 */
interface IFrameElement extends Element {
  /**
   * Props.
   */
  props: Element["props"] & {
    /**
     * An iframe can have a `loading` attribute e.g. To indicate lazy loading.
     */
    loading: string;
  };
}

export const iframe: Processor<IFrameElement, Packages> = {
  name: "amp-iframe",
  priority: 9, // because it should run before the iframe processor from html2react
  test: ({ node }) => node.component === "iframe",
  processor: ({ node }) => {
    node.component = AMPIframe;

    // AMP requires that the iframe is loaded over HTTPS
    node = httpToHttps(node) as IFrameElement;

    delete node.props.loading;

    return node;
  },
};
